﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using WebPALTT.Lib;
using WebPALTT.Lib.Debug;
using System.Reflection;

namespace WebPALTT.UI
{
    public partial class DebugForm : Form
    {
        AppDomain mAppDomain;
        DebugRunner mRunner;
        List<Guid> mBreakpoint = new List<Guid> { };

        public DebugForm(Scenario scenario)
        {
            if (scenario == null)
                throw new NullReferenceException("Scenario cannot be null.");
            if (scenario.Actions.Count == 0)
                throw new Exception("Scenario must contain atleast one action.");

            InitializeComponent();
            tec_Request_CodeEditor.SetHighlighting("C#");
            tec_Response_Content.SetHighlighting("HTML");

            mAppDomain = AppDomain.CreateDomain("DebugDomain");
            mRunner = (DebugRunner)mAppDomain.CreateInstanceFromAndUnwrap(
                Assembly.GetAssembly(typeof(DebugRunner)).Location,
                typeof(DebugRunner).FullName);

            mRunner.StartTest(scenario);
            RefreshTreeView();
        }

        private void DebugForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (mAppDomain != null)
                AppDomain.Unload(mAppDomain);
        }

        private void tsb_NextStep_Click(object sender, EventArgs e)
        {
            if (mRunner.CurrentStep == null)
                return;
            tssl_Status.Text = "Running Step...";
            mRunner.NextStep();
            RefreshTreeView();
            RefreshListView();

            if (mRunner.CurrentStep == null)
                tssl_Status.Text = "Test Completed";            
            else
                tssl_Status.Text = "Ready";
        }

        private void tsb_Continue_Click(object sender, EventArgs e)
        {
            if (mRunner.CurrentStep == null)
                return;

            tssl_Status.Text = "Running Step...";
            bool stop = false;
            while (!stop)
            {
                mRunner.NextStep();
                if (mRunner.CurrentStep == null || mBreakpoint.Contains(mRunner.CurrentStep.Key))
                    stop = true;
            }
            RefreshTreeView();
            RefreshListView();

            if (mRunner.CurrentStep == null)
            {
                tssl_Status.Text = "Test Completed";
                tsb_NextStep.Enabled = false;
                tsb_Continue.Enabled = false;
            }
            else
                tssl_Status.Text = "Ready";
        }

        #region TreeView

        private void ToggleBreakPoint(object sender, EventArgs e)
        {
            TreeNode hitNode = tv_Actions.SelectedNode;

            if (tv_Actions.SelectedNode == null)
                return;
            Guid key;
            if (!Guid.TryParse(tv_Actions.SelectedNode.Name, out key))
                Guid.TryParse(tv_Actions.SelectedNode.Parent.Name, out key);

            if (!mBreakpoint.Contains(key))
                mBreakpoint.Add(key);
            else
                mBreakpoint.Remove(key);
            RefreshTreeView();
            TreeNode[] results = tv_Actions.Nodes.Find(key.ToString(), true);
            if (results.Length > 0)
                tv_Actions.SelectedNode = results[0];
        }

        private void RefreshTreeView()
        {
            if (mRunner == null)
                return;

            Scenario scenario = mRunner.Scenario;
            if (scenario == null)
                return;

            tv_Actions.Nodes.Clear();
            tv_Actions.Nodes.AddRange(GetTreeNodes(scenario.Actions.ToArray()));
            tv_Actions.ExpandAll();

            if (mRunner.CurrentStep != null)
            {
                TreeNode[] results = tv_Actions.Nodes.Find(mRunner.CurrentStep.Key.ToString(), true);
                if (results.Length == 1)
                    results[0].StateImageKey = "Yellow";
            }
        }

        private TreeNode[] GetTreeNodes(ActionItem[] actions)
        {
            List<TreeNode> list = new List<TreeNode> { };
            foreach (ActionItem item in actions)
            {
                TreeNode newnode = null;
                newnode = new TreeNode(item.Name, 1, 1);
                if(item.HasChildren)
                    newnode.Nodes.AddRange(GetTreeNodes(item.Children.ToArray()));
                
                newnode.Name = item.Key.ToString();
                newnode.StateImageKey = "None";
                if (mBreakpoint.Contains(item.Key))
                    newnode.ImageKey = "Red";
                else
                    newnode.ImageKey = "White";
                if (newnode != null)
                    list.Add(newnode);
            }
            return list.ToArray();        
        }

        private void tv_Actions_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                Point pt = new Point(e.X, e.Y);
                TreeNode node = tv_Actions.GetNodeAt(pt);
                if (node != null)
                {
                    tv_Actions.SelectedNode = node;
                    cms_Breakpoints.Show(tv_Actions, pt);
                }
            }
        }

        private void tv_Actions_BeforeSelect(object sender, TreeViewCancelEventArgs e)
        {
            e.Node.SelectedImageKey = e.Node.ImageKey;
        }
        #endregion

        #region ListView

        private void RefreshListView()
        {
            if (mRunner == null)
                return;

            ActionResults[] results = mRunner.Results;
            if (results == null)
                return;

            lv_Results.Items.Clear();
            List<ListViewItem> items = new List<ListViewItem> { };
            for (int i = 0; i < results.Length;i++ )
            {
                ListViewItem lv_item = new ListViewItem(results[i].Name);
                lv_item.SubItems.Add((i+1).ToString());
                lv_item.SubItems.Add(results[i].ActionType.ToString());
                double duration = ((TimeSpan)results[i].Results["DURATION"]).TotalSeconds;
                lv_item.SubItems.Add(duration.ToString("F4"));
                if (results[i].Errors.Count > 0)
                    lv_item.StateImageIndex = 1;
                else
                    lv_item.StateImageIndex = 0;
                lv_item.Name = results[i].Key.ToString();
                items.Add(lv_item);
            }
            lv_Results.Items.AddRange(items.ToArray());
        }

        private void lv_Results_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lv_Results.SelectedItems.Count != 1)
                return;

            ListViewItem selection = lv_Results.SelectedItems[0];
            Guid key = Guid.Parse(selection.Name);
            ActionResults[] results = mRunner.Results;
            ActionResults debugResult = null;
            for (int i = 0; i < results.Length; i++)
                if (Guid.Equals(results[i].Key, key) && results[i].Name.Equals(selection.Text))
                    debugResult = results[i];
            if (debugResult == null)
                throw new Exception("Result item cound not be found.");

            ActionItem actionItem = mRunner.Scenario.Actions.Find(
                delegate(ActionItem item)
                {
                    if(Guid.Equals(item.Key, key))
                        return true;
                    return false;
                }, true);

            if(actionItem == null)
                throw new Exception("Action item cound not be found.");

            tec_Request_CodeEditor.Text = "";
            tec_Request_CodeEditor.Refresh();
            dgv_Result_Result.Rows.Clear();
            dgv_Result_Data.Rows.Clear();
            tec_Response_Content.Text = "";
            tec_Response_Content.Refresh();

            tc_RequestInfo.TabPages.Clear();
            tc_ResultInfo.TabPages.Clear();
            tc_RequestInfo.TabPages.Add(tp_Request_Info);
            tc_ResultInfo.TabPages.Add(tp_Result_Results);
            tc_ResultInfo.TabPages.Add(tp_Result_Data);
            tc_ResultInfo.TabPages.Add(tp_Result_Info);
            
            switch (actionItem.ActionType)
            {
                case ActionType.Action:
                    if (actionItem.CustomType.ToUpper().Equals("WEB REQUEST"))
                    {
                        try
                        {
                            tec_Response_Content.Text = debugResult.Data["Response"].ToString();
                        }
                        catch (Exception)
                        {
                            tec_Response_Content.Text = "[NULL]";
                        }
                        tc_ResultInfo.TabPages.Add(tp_Result_Content);
                    }
                    break;
                case ActionType.Script:
                    tec_Request_CodeEditor.Text = ((ScriptItem)actionItem).VisibleCode;
                    tc_RequestInfo.TabPages.Add(tp_Request_Code);
                    break;
            }
            // Request - Info
            pg_Request_Info.SelectedObject = actionItem;
            // Result - Results
            foreach (KeyValuePair<string, object> kvp in debugResult.Results)
                dgv_Result_Result.Rows.Add(kvp.Key, kvp.Value.ToString());
            foreach(string err in debugResult.Errors)
                    dgv_Result_Result.Rows.Add("Error", err);
            foreach (string warn in debugResult.Warnings)
                    dgv_Result_Result.Rows.Add("Warning", warn);
            // Result - Data
            foreach (KeyValuePair<string, object> kvp in debugResult.Data)
                dgv_Result_Data.Rows.Add(kvp.Key, kvp.Value.ToString());
            // Result - Info
            pg_Result_Info.SelectedObject = debugResult;
        }

        #endregion

        private void DebugForm_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F10)
                tsb_NextStep_Click(null, EventArgs.Empty);
            else if (e.Shift && e.KeyCode == Keys.F5)
                tsb_Stop_Click(null, EventArgs.Empty);            
            else if (e.KeyCode == Keys.F5)
                tsb_Continue_Click(null, EventArgs.Empty);            
            else if (e.KeyCode == Keys.F9)
                ToggleBreakPoint(null, EventArgs.Empty);
            else
                return;
            e.Handled = true;
        }

        private void tsb_Stop_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
